package cn.hpu.mobile_bank.service.impl;

import cn.hpu.mobile_bank.constant.RedisConstants;
import cn.hpu.mobile_bank.domain.Mobile;
import cn.hpu.mobile_bank.domain.PersonInfo;
import cn.hpu.mobile_bank.dto.req.LoginFormReq;
import cn.hpu.mobile_bank.dto.req.RegisterReq;
import cn.hpu.mobile_bank.dto.resp.ApiResult;
import cn.hpu.mobile_bank.dto.resp.LoginResponse;
import cn.hpu.mobile_bank.exception.BusinessException;
import cn.hpu.mobile_bank.exception.CommonErrorEnum;
import cn.hpu.mobile_bank.mapper.MobileMapper;
import cn.hpu.mobile_bank.service.MobileService;
import cn.hpu.mobile_bank.service.PersonInfoService;
import cn.hpu.mobile_bank.utils.RegexUtils;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
* @author DELL
* @description 针对表【mobile】的数据库操作Service实现
* @createDate 2024-06-13 15:23:06
*/
@Service
@Slf4j
public class MobileServiceImpl extends ServiceImpl<MobileMapper, Mobile>
    implements MobileService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private PersonInfoService personInfoService;

    @Autowired
    private MobileMapper mobileMapper;

    @Override
    public ApiResult<LoginResponse> login(LoginFormReq loginFormReq) {
        String telephone = loginFormReq.getTelephone();
        String password = loginFormReq.getPassword();
        //1.校验参数
        if (isValid(telephone, password)) throw new BusinessException(CommonErrorEnum.PARAM_INVALID);
        //2.查询
        Mobile mobile = this.query().eq("telephone", telephone).eq("password", password).one();
        PersonInfo personInfo = personInfoService.query().eq("telephone", telephone).one();
        if(ObjectUtils.isEmpty(mobile) || ObjectUtils.isEmpty(personInfo)) throw new BusinessException(CommonErrorEnum.LOGIN_ERROR);
        //3.生成TOKEN
        String token = UUID.randomUUID().toString();

        //4.组装返回结果
        LoginResponse loginResponse = new LoginResponse();
        loginResponse.setToken(token);
        loginResponse.setPersonId(personInfo.getId());
        loginResponse.setTelephone(telephone);

        //5.将信息存入redis
        //将personInfo转为map
        Map<String, Object> personInfoMap = BeanUtil.beanToMap(loginResponse, new HashMap<>(),
                CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
        stringRedisTemplate.opsForHash().putAll(RedisConstants.LOGIN_USER_KEY + token, personInfoMap);

        return ApiResult.success(loginResponse);
    }

    @Override
    public ApiResult<String> sendCode(String phone) {
        //1.验证手机号
        //1.1.判断手机号是否有效
        if (RegexUtils.isPhoneInvalid(phone)) {
            //2.如果不符合，返回错误信息
            throw new BusinessException(CommonErrorEnum.PARAM_INVALID);
        }
        //1.2.判断手机号是否已经注册
        Mobile mobile = mobileMapper.selectByTelephone(phone);
        if(mobile != null) throw new BusinessException(CommonErrorEnum.PHONE_EXIST_ERROR);

        //3.符合则生成验证码
        String code = RandomUtil.randomNumbers(6);

        //4.保存验证码到redis(设置有效期为2分钟)
        stringRedisTemplate.opsForValue().set(RedisConstants.LOGIN_CODE_KEY + phone,code, RedisConstants.LOGIN_CODE_TTL, TimeUnit.MINUTES);

        //5.发送验证码
        log.debug("发送短信验证码成功,验证码:{}",code);

        //6.返回ok
        return ApiResult.success(code);
    }

    @Override
    public ApiResult<String> checkCode(RegisterReq registerReq) {
        String telephone = registerReq.getTelephone();
        String code = registerReq.getCode();
        isValid(telephone,null);

        String realCode = stringRedisTemplate.opsForValue().get(RedisConstants.LOGIN_CODE_KEY + telephone);
        if(realCode == null || code == null || !realCode.equals(code)) throw new BusinessException(CommonErrorEnum.CODE_ERROR);

        return ApiResult.success();
    }

    @Override
    @Transactional
    public ApiResult<String> register(RegisterReq register) {
        String telephone = register.getTelephone();
        String password = register.getPassword();

        if(ObjectUtils.isEmpty(telephone) || ObjectUtils.isEmpty(password)) throw new BusinessException(CommonErrorEnum.PARAM_INVALID);

        //判断mobile表中是否存在手机号
        Mobile mob = mobileMapper.selectByTelephone(telephone);
        if(mob != null) throw new BusinessException(CommonErrorEnum.PHONE_EXIST_ERROR);

        //插入mobile表
        Mobile mobile = new Mobile();
        mobile.setTelephone(telephone);
        mobile.setPassword(password);
        mobileMapper.insert(mobile);

        PersonInfo personInfo = new PersonInfo();
        personInfo.setTelephone(telephone);
        personInfoService.save(personInfo);

        return ApiResult.success();
    }

    private boolean isValid(String telephone, String password){
        if(password == null){
            return RegexUtils.isPhoneInvalid(telephone);
        }
        //如果不符合，返回错误信息
        return (RegexUtils.isPassWordInvalid(password) || RegexUtils.isPhoneInvalid(telephone));
    }
}




